package org.xx.armory.swing.builders;

import org.xx.armory.commons.SysUtils;
import org.xx.armory.swing.ResourceLoader;

import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static org.xx.armory.commons.Validators.notBlank;

/**
 * 和用户界面绑定的加载器。
 */
public final class UIModelLoader {
    private static final Map<String, UIModel> MODELS = createModels();

    private UIModelLoader() {
    }

    private static Map<String, UIModel> createModels() {
        return new ConcurrentHashMap<>();
    }

    /**
     * 加载资源并更新指定的用户界面对象。
     *
     * @param clazz
     *         用户界面对象的类型。
     * @return 已加载的用户界面模型，如果无法加载则返回{@code null}。
     * @throws UncheckedIOException
     *         如果指定类型的用户界面资源不存在。
     * @see #load(String)
     */
    public static UIModel load(
            Class<?> clazz
    ) {
        return load(clazz.getName());
    }

    /**
     * 加载资源并更新指定的用户界面对象。
     *
     * @param uiName
     *         用户界面的名字，如果是相对路径则看作相对于类路径。
     * @return 已加载的用户界面模型，如果无法加载则返回{@code null}。
     * @throws IllegalArgumentException
     *         如果参数{@code uiName}是{@code null}或者只包含空白字符。
     * @throws UncheckedIOException
     *         如果指定名字的用户界面资源不存在。
     */
    public static UIModel load(
            String uiName
    ) {
        uiName = notBlank(uiName, "uiName").trim();
        return MODELS.computeIfAbsent(uiName, UIModelLoader::loadNew);
    }

    /**
     * 加载资源。
     *
     * @param uiName
     *         用户界面的名字，如果是相对路径则看作相对于类路径。
     * @return 已加载的资源模型，如果加载失败则返回{@code null}。
     * @throws UncheckedIOException
     *         如果指定名字的用户界面资源不存在。
     */
    private static UIModel loadNew(
            String uiName
    ) {
        final String resourceName = uiName + ".rc";

        final List<UIModel> results = new ArrayList<>();

        try (final InputStream stream = ResourceLoader.getInstance().loadStream(resourceName)) {
            new XmlUIModelParser().parse(stream, results);
        } catch (IOException ex) {
            throw new UncheckedIOException(ex);
        }

        return SysUtils.getOrDefault(results, 0, null);
    }
}
